pub fn time_info(date_str: &str) -> String {
    let (year, month, day) = parse_date(date_str);

    println!("{}, {}, {}", year, month, day);

    let week = calculate_week(year, month, day);
    let days_remaining = calculate_remaining_days(year, month, day);
    let days_to_spring = calculate_days_to_spring(year, month, day);

    format!("{},{},{}", week, days_remaining, days_to_spring)
}

fn parse_date(date_str: &str) -> (i32, i32, i32) {
    let parts: Vec<&str> = date_str.split('-').collect();
    (
        parts[0].parse().unwrap(),
        parts[1].parse().unwrap(),
        parts[2].parse().unwrap(),
    )
}

fn is_leap_year(year: i32) -> bool {
    (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
}

fn days_in_month(year: i32, month: i32) -> i32 {
    match month {
        4 | 6 | 9 | 11 => 30,
        2 => {
            if is_leap_year(year) {
                29
            } else {
                28
            }
        }
        _ => 31,
    }
}

fn calculate_week(year: i32, month: i32, day: i32) -> i32 {
    let mut y = year;
    let mut m = month;

    if m <= 2 {
        m += 12;
        y -= 1;
    }

    let k = y % 100;
    let j = y / 100;

    let h = (day + ((13 * (m + 1)) / 5) + k + (k / 4) + (j / 4) - (2 * j)) % 7;
    let day_of_week = ((h + 5) % 7) + 1;

    let mut days = day;
    for i in 1..month {
        days += days_in_month(year, i);
    }

    let mut week = ((days - day_of_week + 10) / 7) as i32;

    if week < 1 {
        let last_year_days = if is_leap_year(year - 1) { 366 } else { 365 };
        let last_year_last_week = (last_year_days - day_of_week + 10) / 7;
        week = last_year_last_week as i32;
    } else if week > 52 {
        if month == 12 && day >= 29 {
            week = 1;
        }
    }

    week
}

fn calculate_remaining_days(year: i32, month: i32, day: i32) -> i32 {
    let mut remaining = 0;

    remaining += days_in_month(year, month) - day;

    for m in (month + 1)..=12 {
        remaining += days_in_month(year, m);
    }

    remaining
}

fn calculate_days_to_spring(year: i32, month: i32, day: i32) -> i32 {
    let spring_dates = [
        (2012, 1, 23),
        (2013, 2, 10),
        (2014, 1, 31),
        (2015, 2, 19),
        (2020, 1, 25),
        (2021, 2, 12),
        (2022, 2, 1),
        (2024, 2, 10),
        (2025, 1, 29),
        (2026, 2, 17),
    ];

    let mut target_date = None;

    if spring_dates
        .iter()
        .any(|&(sy, sm, sd)| sy == year && sm == month && sd == day)
    {
        return 0;
    }

    if spring_dates
        .iter()
        .any(|&(sy, sm, sd)| sy == year && sm == month && sd == (day - 1))
    {
        for &(sy, sm, sd) in spring_dates.iter() {
            if sy > year {
                target_date = Some((sy, sm, sd));
                break;
            }
        }
    } else {
        for &(sy, sm, sd) in spring_dates.iter() {
            if sy > year || (sy == year && sm > month) || (sy == year && sm == month && sd > day) {
                target_date = Some((sy, sm, sd));
                break;
            }
        }
    }

    if let Some((target_year, target_month, target_day)) = target_date {
        let mut days = 0;

        if target_year == year {
            if target_month == month {
                days = target_day - day;
            } else {
                days = days_in_month(year, month) - day;
                for m in (month + 1)..target_month {
                    days += days_in_month(year, m);
                }
                days += target_day;
            }
        } else {
            days = days_in_month(year, month) - day;
            for m in (month + 1)..=12 {
                days += days_in_month(year, m);
            }
            for m in 1..target_month {
                days += days_in_month(target_year, m);
            }
            days += target_day;
        }

        days - 1
    } else {
        0
    }
}
